package com.ccloud.api.system.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ccloud.api.system.domain.SysPermission;
import com.ccloud.api.system.domain.SysRole;
import com.ccloud.api.system.domain.SysUser;
import com.ccloud.api.system.domain.SysUserRole;
import com.ccloud.api.system.mapper.SysPermissionMapper;
import com.ccloud.api.system.mapper.SysRoleMapper;
import com.ccloud.api.system.mapper.SysUserMapper;
import com.ccloud.api.system.mapper.SysUserRoleMapper;
import com.ccloud.api.system.model.LoginUser;
import com.ccloud.api.system.model.SysLoginModel;
import com.ccloud.api.system.service.ISysDictService;
import com.ccloud.api.system.service.ISysLogService;
import com.ccloud.api.system.service.ISysUserService;
import com.ccloud.common.core.constant.CacheConstants;
import com.ccloud.common.core.constant.CommonConstant;
import com.ccloud.common.core.constant.Constants;
import com.ccloud.common.core.reqres.response.Result;
import com.ccloud.common.core.utils.PasswordUtil;
import com.ccloud.common.redis.cache.ZCache;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author chentailai
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Resource
    private SysUserMapper userMapper;
    @Resource
    private SysPermissionMapper sysPermissionMapper;
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    @Resource
    private ISysLogService logService;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private ISysDictService sysDictService;
    @Resource
    private ZCache zCache;

    @Override
    public Result<Map<String, Object>> login(SysLoginModel sysLoginModel) {
        Result<Map<String, Object>> result;
        String username = sysLoginModel.username();
        String password = sysLoginModel.password();

        String captcha = sysLoginModel.captcha();
        if (captcha == null) {
            return Result.error("验证码无效");
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = DigestUtils.md5DigestAsHex((lowerCaseCaptcha + sysLoginModel.checkKey()).getBytes());
        String checkCode = zCache.get(realKey, String.class);
        if (lowerCaseCaptcha.equals(CommonConstant.CAPTCHA_BACK_DOOR)) {
            log.info("[system] 使用验证码后门登录...");
        } else if (checkCode == null || !checkCode.equals(lowerCaseCaptcha)) {
            return Result.error("验证码错误");
        }
        //1. 校验用户是否有效
        SysUser sysUser = getUserByName(username);
        result = checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //2. 校验用户名或密码是否正确
        String sysPassword = sysUser.getPassword();
        if (!new BCryptPasswordEncoder().matches(password, sysPassword)) {
            result.error500("用户名或密码错误");
            return result;
        }

        //用户登录信息
        userInfo(sysUser, result);
        logService.addLog("用户: " + sysUser.getRealname() + ",登录成功！", CommonConstant.LOG_TYPE_1,
                null, sysUser);
        return result;
    }

    @Override
    public Result<Map<String, Object>> phoneLogin(Map<String, String> phoneLoginParam) {
        Result<Map<String, Object>> result;
        String phone = phoneLoginParam.get("mobile");

        //校验用户有效性
        SysUser sysUser = getUserByPhone(phone);
        result = checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        String smsCode = phoneLoginParam.get("captcha");
        Object code = zCache.get(phone, String.class);
        if (!smsCode.equals(code)) {
            result.setMessage("手机验证码错误");
            return result;
        }
        //用户信息
        userInfo(sysUser, result);
        //添加日志
        logService.addLog("用户名: " + sysUser.getUsername() + ",登录成功！", CommonConstant.LOG_TYPE_1,
                null, sysUser);
        return result;
    }

    @Override
    public Result<Map<String, Object>> smsLogin(Map<String, String> smsParam) {
        Result<Map<String, Object>> result = new Result<>();
        String mobile = smsParam.get("mobile");
        //手机号模式 登录模式: "2"  注册模式: "1"
        String smsMode = smsParam.get("smsmode");
        log.info(mobile);
        if (StringUtils.isEmpty(mobile)) {
            result.setMessage("手机号不允许为空！");
            result.setSuccess(false);
            return result;
        }
        String object = zCache.get(mobile, String.class);
        if (object != null) {
            result.setMessage("验证码10分钟内，仍然有效！");
            result.setSuccess(false);
            return result;
        }
        //随机数
        String captcha = RandomUtil.randomNumbers(6);
        Map<String, String> obj = new HashMap<>(2);
        obj.put("code", captcha);
        try {
            boolean b = false;
            //注册模板
            if (CommonConstant.SMS_TPL_TYPE_1.equals(smsMode)) {
                SysUser sysUser = getUserByPhone(mobile);
                if (sysUser != null) {
                    result.error500(" 手机号已经注册，请直接登录！");
                    return result;
                }
                // send msg
            } else {
                //登录模式，校验用户有效性
                SysUser sysUser = getUserByPhone(mobile);
                result = checkUserIsEffective(sysUser);
                if (!result.isSuccess()) {
                    String message = result.getMessage();
                    if ("该用户不存在，请注册".equals(message)) {
                        result.error500("该用户不存在或未绑定手机号");
                    }
                    return result;
                }

                /**
                 * smsmode 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
                 */
                if (CommonConstant.SMS_TPL_TYPE_0.equals(smsMode)) {
                    //登录模板
                    // send msg
                } else if (CommonConstant.SMS_TPL_TYPE_2.equals(smsMode)) {
                    //忘记密码模板
                    // send msg
                }
            }

            if (!b) {
                result.setMessage("短信验证码发送失败,请稍后重试");
                result.setSuccess(false);
                return result;
            }
            //验证码10分钟内有效
            zCache.put(mobile, captcha, 600);
            result.setSuccess(true);

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("短信接口未配置，请联系管理员！");
            return result;
        }
        return result;
    }

    @Override
    @CacheEvict(value = {CacheConstants.SYS_USERS_CACHE}, allEntries = true)
    public Result<?> resetPassword(String username, String oldPassword, String newPassword, String confirmPassword) {
        SysUser user = userMapper.getUserByName(username);
        if (user == null) {
            return Result.error("用户不存在!");
        }
        String passwordEncode = PasswordUtil.encrypt(username, oldPassword, user.getSalt());
        if (!user.getPassword().equals(passwordEncode)) {
            return Result.error("旧密码输入错误!");
        }
        if (StringUtils.isEmpty(newPassword)) {
            return Result.error("新密码不允许为空!");
        }
        if (!newPassword.equals(confirmPassword)) {
            return Result.error("两次输入密码不一致!");
        }
        String password = PasswordUtil.encrypt(username, newPassword, user.getSalt());
        this.userMapper.update(new SysUser().setPassword(password), new LambdaQueryWrapper<SysUser>().eq(SysUser::getId, user.getId()));
        return Result.ok();
    }

    @Override
    @CacheEvict(value = {CacheConstants.SYS_USERS_CACHE}, allEntries = true)
    public Result<?> changePassword(SysUser sysUser) {
        String salt = RandomUtil.randomString(8);
        String password = sysUser.getPassword();
        String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), password, salt);
        SysUser user = new SysUser();
        user.setSalt(salt);
        user.setId(sysUser.getId());
        user.setPassword(passwordEncode);
        this.userMapper.updateById(user);
        return Result.ok();
    }

    @Override
    @CacheEvict(value = {CacheConstants.SYS_USERS_CACHE}, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteUser(String userId) {
        //1.删除用户
        this.removeById(userId);
        return false;
    }

    @Override
    @CacheEvict(value = {CacheConstants.SYS_USERS_CACHE}, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBatchUsers(String userIds) {
        //1.删除用户
        this.removeByIds(Arrays.asList(userIds.split(",")));
        return false;
    }

    @Override
    public SysUser getUserByName(String username) {
        return userMapper.getUserByName(username);
    }

    @Override
    @Cacheable(cacheNames = CacheConstants.SYS_USERS_CACHE, key = "#username")
    public LoginUser getLoginUserByName(String username) {
        if (StringUtils.isEmpty(username)) {
            return null;
        }
        LoginUser loginUser = new LoginUser();
        SysUser sysUser = userMapper.getUserByName(username);
        if (sysUser == null) {
            return null;
        }
        BeanUtils.copyProperties(sysUser, loginUser);
        return loginUser;
    }


    @Override
    @Transactional
    public void addUserWithRole(SysUser user) {
        this.save(user);
        saveUserRoles(user);
    }

    private void saveUserRoles(SysUser user) {
        if (StringUtils.isNotEmpty(user.getRoles())) {
            String[] arr = user.getRoles().split(",");
            for (String roleId : arr) {
                SysUserRole userRole = new SysUserRole(user.getId(), Integer.parseInt(roleId));
                sysUserRoleMapper.insert(userRole);
            }
        }
    }

    @Override
    @CacheEvict(value = {CacheConstants.SYS_USERS_CACHE}, allEntries = true)
    @Transactional
    public void editUserWithRole(SysUser user) {
        this.updateById(user);
        //先删后加
        sysUserRoleMapper.delete(new QueryWrapper<SysUserRole>().lambda().eq(SysUserRole::getUserId, user.getId()));
        saveUserRoles(user);
    }


    @Override
    public List<String> getRole(String username) {
        return sysUserRoleMapper.getRoleByUserName(username);
    }

    /**
     * 通过用户名获取用户角色集合
     *
     * @param username 用户名
     * @return 角色集合
     */
    @Override
    public Set<String> getUserRolesSet(String username) {
        // 查询用户拥有的角色集合
        List<String> roles = sysUserRoleMapper.getRoleByUserName(username);
        log.info("-------通过数据库读取用户拥有的角色Rules------username： " + username + ",Roles size: " + (roles == null ? 0 : roles.size()));
        return new HashSet<>(roles);
    }

    /**
     * 通过用户名获取用户权限集合
     *
     * @param username 用户名
     * @return 权限集合
     */
    @Override
    public Set<String> getUserPermissionsSet(String username) {
        Set<String> permissionSet = new HashSet<>();
        List<SysPermission> permissionList = sysPermissionMapper.queryByUser(username);
        for (SysPermission po : permissionList) {
//			// TODO URL规则有问题？
//			if (oConvertUtils.isNotEmpty(po.getUrl())) {
//				permissionSet.add(po.getUrl());
//			}
            if (StringUtils.isNotEmpty(po.getPerms())) {
                permissionSet.add(po.getPerms());
            }
        }
        log.info("-------通过数据库读取用户拥有的权限Perms------username： " + username + ",Perms size: " + (permissionSet == null ? 0 : permissionSet.size()));
        return permissionSet;
    }

    @Override
    public IPage<SysUser> getUserByRoleId(Page<SysUser> page, String roleId, String username) {
        return userMapper.getUserByRoleId(page, roleId, username);
    }

    @Override
    public SysUser getUserByPhone(String phone) {
        return userMapper.getUserByPhone(phone);
    }


    @Override
    public SysUser getUserByEmail(String email) {
        return userMapper.getUserByEmail(email);
    }

    /**
     * 校验用户是否有效
     *
     * @param sysUser
     * @return
     */
    @Override
    public Result<Map<String, Object>> checkUserIsEffective(SysUser sysUser) {
        Result<Map<String, Object>> result = new Result<>();
        //情况1：根据用户信息查询，该用户不存在
        if (sysUser == null) {
            result.error500("该用户不存在，请注册");
            logService.addLog("用户登录失败，用户不存在！", CommonConstant.LOG_TYPE_1, null, null);
            return result;
        }
        //情况2：根据用户信息查询，该用户已注销
        if (CommonConstant.DEL_FLAG_1.equals(sysUser.getDelFlag())) {
            logService.addLog("用户登录失败，用户名:" + sysUser.getUsername() + "已注销！",
                    CommonConstant.LOG_TYPE_1, null, sysUser);
            result.error500("该用户已注销");
            return result;
        }
        //情况3：根据用户信息查询，该用户已冻结
        if (CommonConstant.USER_FREEZE.equals(sysUser.getStatus())) {
            logService.addLog("用户登录失败，用户名:" + sysUser.getUsername() + "已冻结！",
                    CommonConstant.LOG_TYPE_1, null, sysUser);
            result.error500("该用户已冻结");
            return result;
        }
        return result;
    }

    @Override
    public List<SysUser> queryLogicDeleted() {
        return userMapper.selectLogicDeleted();
    }

    @Override
    public boolean revertLogicDeleted(List<String> userIds, SysUser updateEntity) {
        String ids = String.format("%s", String.join("','", userIds));
        return userMapper.revertLogicDeleted(ids, updateEntity) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeLogicDeleted(List<String> userIds) {
        // 1. 删除用户
        int line = userMapper.deleteLogicDeleted(userIds);
        //3. 删除用户角色关系
        line += sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, userIds));
        return line != 0;
    }

    @Override
    public void saveThirdUser(SysUser sysUser) {
        //保存用户
        baseMapper.insert(sysUser);
        //获取第三方角色
        SysRole sysRole = sysRoleMapper.selectOne(new LambdaQueryWrapper<SysRole>().eq(SysRole::getRoleCode, "third_role"));
        //保存用户角色
        SysUserRole userRole = new SysUserRole();
        userRole.setRoleId(sysRole.getId());
        userRole.setUserId(sysUser.getId());
        sysUserRoleMapper.insert(userRole);
    }

    /**
     * 用户信息
     *
     * @param sysUser SysUser
     * @param result  Result<Map<String, Object>>
     */
    private void userInfo(SysUser sysUser, Result<Map<String, Object>> result) {
        Map<String, Object> obj = Maps.newHashMap(new HashMap<>(3));

        // 获取用户部门信息
        obj.put("userInfo", sysUser);
        obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
        obj.put("roles", getUserRolesSet(sysUser.getUsername()));
        result.setResult(obj);
        result.success(Constants.LOGIN_SUCCESS);
    }

}
